# gozerbot/commands.py
#
#

""" implement commands """

__copyright__ = 'this file is in the public domain'

from gozerbot.generic import rlog, calledfrom, handle_exception
from gozerbot.aliases import aliases
import gozerbot.thr as thr
import sys, re, copy, types

class Command(object):

    """ a command """

    def __init__(self, func, perm, plugname, speed, threaded):
        self.func = func
        if type(perm) == types.ListType:
            self.perms = list(perm)
        else:
            self.perms = [perm, ]
        self.plugname = plugname
        self.speed = copy.deepcopy(speed)
        self.threaded = copy.deepcopy(threaded)

class Commands(dict):

    """ commands object is a dict containing the commands """

    def size(self):
        """ nr of commands """
        return len(self)

    def list(self, perm):
        """ list commands with permission perm """
        result = []
        perm = perm.upper()
        for name, cmnd in self.items():
            if perm in cmnd.perms:
                result.append(name)
        return result

    def permoverload(self, funcname, perm):
        """ overload permission of function with funcname  """
        perm = perm.upper()
        for com in self.values():
            if com.func.func_name == funcname:
                if perm not in com.perms:
                    com.perms.append(perm)
                return 1

    def add(self, cmnd, func, perm, speed=5, threaded=1):
        """ add a command """
        # plugin where the command is added
        plugname = calledfrom(sys._getframe())
        rlog(-3, 'commands', 'added %s (%s) ' % (cmnd, plugname))
        # add command
        self[cmnd.lower()] = Command(func, perm, plugname, speed, threaded)

    def apropos(self, what):
        """ search for command """
        result = []
        for cmnd in self.keys():
            if re.search(what, cmnd):
                result.append(cmnd)
        return result

    def unload(self, plugname):
        """ unload plugin commands """
        results = []
        # look for the commands registerd in plugin
        for name, cmnd in self.iteritems():
            if cmnd.plugname == plugname:
                results.append(name)
        got = 0
        # remove commands
        for name in results:
            del self[name]
            rlog(-3, 'commands', 'unloaded %s (%s)' % (name, plugname))
            got = 1
        if got:
            return 1

    def whereis(self, what):
        """ locate command """
        result = []
        for name, cmnd in self.iteritems():
            if name == what:
                if not cmnd.plugname in result:
                    result.append(cmnd.plugname)
        return result

    def perms(self, name):
        """ get permission of command """
        name = name.lower()
        if self.has_key(name):
            return self[name].perms

    def setperm(self, name, perm):
        """ set permission of command """
        name = name.lower()
        perm = perm.upper()
        if self.has_key(name):
            if perm not in self[name].perms:
                self[name].perms.append(perm)
            return 1

    def getalias(self, txt):
        """ check if alias is available """
        alias = None
        try:
            cmnd = txt.split()[0]
            alias = aliases.data[cmnd]
        except:
            pass
        return alias

    def iscommand(self, name):
        """ check if name is command """
        alias = self.getalias(name)
        return self.has_key(alias.lower())

    def getcommand(self, txt):
        """ return commands matching with txt """
        textlist = txt.split()
        if not textlist:
            return None
        cmnd = textlist[0].lower()
        alias = self.getalias(cmnd)
        if alias:
            cmnd = alias.split()[0]
        if self.has_key(cmnd):
            com = self[cmnd] # the command
            return com
        else:
            return None

    def dispatch(self, com, txt):
        """ dispatch command """
        if com.threaded:
            thr.start_new_thread(com.func, (txt, ))
        else:
            try:
                com.func(txt)
            except Exception, ex:
                handle_exception()
                return 0
        return 1

class Botcommands(Commands):

    """ commands for the bot aka dispatch on ircevent """

    def dispatch(self, com, bot, ievent):
        """ dispatch on ircevent """
        if bot.stopped:
            return 0
        # execute command
        ievent.usercmnd = 1
        rlog(10, 'commands', '%s (%s) executing %s' % (ievent.nick, \
ievent.userhost, ievent.txt))
        if com.threaded:
            thr.start_bot_command(com.func, (bot, ievent))
        else:
            try:
                com.func(bot, ievent)
            except Exception, ex:
                handle_exception(ievent)
                return 0
        return 1

cmnds = Botcommands()
